﻿using System.Collections.Generic;
using System.Linq;

using NAudio.Wave;
using NAudio.Wave.SampleProviders;
using iStudio.Structure.Engine;

namespace iStudio.Engine
{
    /// <summary>
    /// NAudio Multiplexing provider for iStudio
    /// </summary>
    internal class NAudioMultiplexer : INAudioStream, IOutputProvider
    {
        private readonly MultiplexingSampleProvider _multiplexer;
        private readonly IList<INAudioStream> _sources;
        private readonly OutputSampleProvider _output;

        public NAudioMultiplexer (IList<INAudioStream> sources, int numberOfOutputChannels)
        {
            _sources = sources;
            _output = new OutputSampleProvider ();

            _multiplexer = new MultiplexingSampleProvider (sources, numberOfOutputChannels);
        }

        public NAudioMultiplexer (IEnumerable<NAudioMixer> sources, int numberOfOutputChannels)
        {
            _sources = new List<INAudioStream>();

            foreach (NAudioMixer mixer in sources)
            {
                _sources.Add(mixer);
            }

            _output = new OutputSampleProvider();

            _multiplexer = new MultiplexingSampleProvider(_sources, numberOfOutputChannels);
        }

        public long Position
        {
            get
            {
                return _sources[0].Position;
            }
            set
            {
                if (_sources[0].Position != value)
                {
                    foreach (INAudioStream stream in _sources)
                    {
                        stream.Position = value;
                    }
                }
            }
        }

        public long Length
        {
            get
            {
                return _sources.Select(stream => stream.Length).Concat(new long[] {0}).Max();
            }
        }

        public void ConnectInputToOutput (int inputChannel, int outputChannel)
        {
            _multiplexer.ConnectInputToOutput(inputChannel, outputChannel);
        }

        public int InputChannelCount
        {
            get
            {
                return _multiplexer.InputChannelCount;
            }
        }

        public int OutputChannelCount
        {
            get
            {
                return _multiplexer.OutputChannelCount;
            }
        }

        public WaveFormat WaveFormat
        {
            get
            {
                return _multiplexer.WaveFormat;
            }
        }

        public int Read(float[] buffer, int offset, int count)
        {
            int readSamples = _multiplexer.Read(buffer, offset, count);

            _output.Process (buffer, offset, count);

            return readSamples;
        }

        public OutputSampleProvider Output
        {
            get
            {
                return _output;
            }
        }
    }
}
